﻿using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace XiaoSe.Image.Drawing.Imaging
{
    /// <summary>
    /// 图片帮助类
    /// </summary>
    public class ImageHelper
    {
        /// <summary>
        /// 根据流获取图片的宽度高度
        /// </summary>
        /// <param name="imgStream">流</param>
        /// <returns></returns>
        public WidthHeight GetWidthHeight(Stream imgStream)
        {
            var wh = new WidthHeight();
            System.Drawing.Image image = System.Drawing.Image.FromStream(imgStream);
            wh.Width = image.Width;
            wh.Height = image.Height;
            image.Dispose();
            return wh;
        }
        /// <summary>
        /// 根据图片绝对路径获取图片的宽度高度
        /// </summary>
        /// <param name="imagePath">图片绝对路径</param>
        /// <returns></returns>
        public WidthHeight GetWidthHeight(string imagePath)
        {
            if (!File.Exists(imagePath))
            {
                return default(WidthHeight);
            }
            Stream s = File.Open(imagePath, FileMode.Open);
            WidthHeight wh = GetWidthHeight(s);
            s.Close();
            return wh;
        }
        /// <summary>
        /// 裁剪指定流指定始点和终点之间部分
        /// </summary>
        /// <param name="imgStream">流</param>
        /// <param name="newsImageSavePath">裁剪生成的图片保存路径</param>
        /// <param name="startx">始点X坐标</param>
        /// <param name="starty">始点Y坐标</param>
        /// <param name="endx">终点X坐标</param>
        /// <param name="endy">终点Y坐标</param>
        /// <param name="waterString">水印文字(为""表示不使用水印)</param>
        /// <param name="point1">水印文字左上角位置</param>
        /// <param name="waterImgPath">水印图片绝对路径(为""表示不使用水印)</param>
        /// <param name="point2">水印图片左上角位置</param>
        /// <returns>成功返回True,否则False</returns>
        public bool CutImage(Stream imgStream, string newsImageSavePath, int startx, int starty, int endx, int endy, string waterString, Point point1, string waterImgPath, Point point2)
        {
            try
            {
                //GetWidthHeight(imgStream);
                var initimage = System.Drawing.Image.FromStream(imgStream);
                var newimage = new Bitmap(endx - startx, endy - starty);
                var graphics = Graphics.FromImage(newimage);
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                var fromR = new Rectangle(startx, starty, endx - startx, endy - starty);
                var toR = new Rectangle(0, 0, endx - startx, endy - starty);
                graphics.DrawImage(initimage, toR, fromR, GraphicsUnit.Pixel);
                if (!string.IsNullOrEmpty(waterString.Trim()))
                {
                    AddStringToImage(graphics, waterString, point1);
                }
                if (!string.IsNullOrEmpty(waterImgPath.Trim()))
                {
                    AddWaterImg(graphics, waterImgPath, point2);
                }
                newimage.Save(newsImageSavePath);
                newimage.Dispose();
                initimage.Dispose();
                graphics.Dispose();
                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// 裁剪指定流指定始点和终点之间部分
        /// </summary>
        /// <param name="imagePath">图片文件绝对路径</param>
        /// <param name="newsImageSavePath">裁剪生成的图片保存路径</param>
        /// <param name="startx">始点X坐标</param>
        /// <param name="starty">始点Y坐标</param>
        /// <param name="endx">终点X坐标</param>
        /// <param name="endy">终点Y坐标</param>
        /// <param name="waterString">水印文字(为""表示不使用水印)</param>
        /// <param name="point1">水印文字左上角位置</param>
        /// <param name="waterImgPath">水印图片绝对路径(为""表示不使用水印)</param>
        /// <param name="point2">水印图片左上角位置</param>
        /// <returns>成功返回True,否则False</returns>
        public bool CutImage(string imagePath, string newsImageSavePath, int startx, int starty, int endx, int endy, string waterString, Point point1, string waterImgPath, Point point2)
        {
            if (!File.Exists(imagePath))
            {
                return false;
            }
            Stream s = File.Open(imagePath, FileMode.Open);
            bool flag = CutImage(s, newsImageSavePath, startx, starty, endx, endy, waterString, point1, waterImgPath, point2);
            s.Close();
            return flag;
        }
        /// <summary>
        /// 缩放图片
        /// </summary>
        /// <param name="imgStream">流</param>
        /// <param name="newsImageSavePath">缩放生成的图片保存路径</param>
        /// <param name="standard">为0时则宽度跟高度用各自的参数缩放；为1时则以MaxWidth为标准按比例缩放；为2时则以MaxHeight为标准按比例缩放</param>
        /// <param name="maxWidth">最大宽度</param>
        /// <param name="maxHeight">最大高度</param>
        /// <param name="waterString">水印文字(为""表示不使用水印)</param>
        /// <param name="point1">水印文字左上角位置</param>
        /// <param name="waterImgPath">水印图片绝对路径(为""表示不使用水印)</param>
        /// <param name="point2">水印图片左上角位置</param>
        /// <returns>成功返回True,否则False</returns>
        public bool ZoomImage(Stream imgStream, string newsImageSavePath, int standard, int maxWidth, int maxHeight, string waterString, Point point1, string waterImgPath, Point point2)
        {
            if (imgStream == null || newsImageSavePath == "" || (standard != 0 && standard != 1 && standard != 2) || maxWidth <= 0 || maxHeight <= 0)
            {
                return false;
            }
            WidthHeight wh = GetWidthHeight(imgStream);
            int newwidth = 0;
            int newheight = 0;
            if (standard == 0)
            {
                newwidth = wh.Width <= maxWidth ? wh.Width : maxWidth;
                newheight = wh.Height <= maxHeight ? wh.Height : maxHeight;
            }
            if (standard == 1)
            {
                if (wh.Width <= maxWidth)
                {
                    newwidth = wh.Width;
                    newheight = wh.Height;
                }
                else
                {
                    newwidth = maxWidth;
                    newheight = (int)(((float)maxWidth / wh.Width) * wh.Height);
                }
            }
            if (standard == 2)
            {
                if (wh.Height <= maxHeight)
                {
                    newheight = wh.Height;
                    newwidth = wh.Width;
                }
                else
                {
                    newwidth = (int)(((float)maxHeight / wh.Height) * wh.Width);
                    newheight = maxHeight;
                }
            }
            try
            {
                System.Drawing.Image initimage = System.Drawing.Image.FromStream(imgStream);
                System.Drawing.Image newimage = new Bitmap(newwidth, newheight);
                var graphics = Graphics.FromImage(newimage);
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                var fromR = new Rectangle(0, 0, wh.Width, wh.Height);
                var toR = new Rectangle(0, 0, newwidth, newheight);
                graphics.DrawImage(initimage, toR, fromR, GraphicsUnit.Pixel);
                if (!string.IsNullOrEmpty(waterString.Trim()))
                {
                    AddStringToImage(graphics, waterString, point1);
                }
                if (!string.IsNullOrEmpty(waterImgPath.Trim()))
                {
                    AddWaterImg(graphics, waterImgPath, point2);
                }
                newimage.Save(newsImageSavePath);
                newimage.Dispose();
                initimage.Dispose();
                graphics.Dispose();
            }
            catch
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 缩放图片
        /// </summary>
        /// <param name="imagePath">图片文件绝对路径</param>
        /// <param name="newsImageSavePath">缩放生成的图片保存路径</param>
        /// <param name="standard">为0时则宽度跟高度用各自的参数缩放；为1时则以MaxWidth为标准按比例缩放；为2时则以MaxHeight为标准按比例缩放</param>
        /// <param name="maxWidth">最大宽度，为小数时则按百分比</param>
        /// <param name="maxHeight">最大宽度，为小数时则按百分比</param>
        /// <param name="waterString">水印文字(为""表示不使用水印)</param>
        /// <param name="point1">水印文字左上角位置</param>
        /// <param name="waterImgPath">水印图片绝对路径(为""表示不使用水印)</param>
        /// <param name="point2">水印图片左上角位置</param>
        /// <returns></returns>
        public bool ZoomImage(string imagePath, string newsImageSavePath, int standard, int maxWidth, int maxHeight, string waterString, Point point1, string waterImgPath, Point point2)
        {
            if (!File.Exists(imagePath))
            {
                return false;
            }
            Stream s = File.Open(imagePath, FileMode.Open);
            bool flag = ZoomImage(s, newsImageSavePath, standard, maxWidth, maxHeight, waterString, point1, waterImgPath, point2);
            s.Close();
            return flag;
        }
        /// <summary>
        /// 给图片添加文字
        /// </summary>
        /// <param name="graphics">Graphics对象</param>
        /// <param name="waterString">文字内容</param>
        /// <param name="point">要添加文字的左上角位置</param>
        private void AddStringToImage(Graphics graphics, string waterString, Point point)
        {
            var f = new Font("Arial", 16);
            var brush = new LinearGradientBrush(new Rectangle(0, 0, 100, 20), Color.FromArgb(150, 0, 0, 0), Color.FromArgb(150, 0, 0, 0), 1.2f, true);
            graphics.DrawString(waterString, f, brush, point);
            f.Dispose();
        }

        /// <summary>
        /// 添加水印图片
        /// </summary>
        /// <param name="graphics">Graphics对象</param>
        /// <param name="waterImgPath">水印图片绝对路径</param>
        /// <param name="point">水印图片的左上角位置</param>
        private void AddWaterImg(Graphics graphics, string waterImgPath, Point point)
        {
            if (!File.Exists(waterImgPath))
            {
                return;
            }
            using (System.Drawing.Image waterimg = System.Drawing.Image.FromFile(waterImgPath))
            {
                //透明属性
                var imgAttributes = new ImageAttributes();
                var colorMap = new ColorMap
                    {
                        OldColor = Color.FromArgb(255, 0, 255, 0),
                        NewColor = Color.FromArgb(0, 0, 0, 0)
                    };
                ColorMap[] remapTable = { colorMap };
                imgAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
                float[][] colorMatrixElements = { 
                                   new[] {1.0f,  0.0f,  0.0f,  0.0f, 0.0f},
                                   new[] {0.0f,  1.0f,  0.0f,  0.0f, 0.0f},
                                   new[] {0.0f,  0.0f,  1.0f,  0.0f, 0.0f},
                                   new[] {0.0f,  0.0f,  0.0f,  0.3f, 0.0f},//透明度:0.5
                                   new[] {0.0f,  0.0f,  0.0f,  0.0f, 1.0f}
                                };
                var wmColorMatrix = new ColorMatrix(colorMatrixElements);
                imgAttributes.SetColorMatrix(wmColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
                graphics.DrawImage(waterimg, new Rectangle(point.X, point.Y, waterimg.Width, waterimg.Height), 0, 0, waterimg.Width, waterimg.Height, GraphicsUnit.Pixel, imgAttributes);
            }
        }
        /// <summary>
        /// 添加水印图片
        /// </summary>
        /// <param name="oldImagePath">要添加水印图片的图片的绝对路径</param>
        /// <param name="waterImagePath">水印图片绝对路径</param>
        /// <param name="newImageSavePath">新图片保存路径</param>
        /// <param name="point">水印图片左上角位置</param>
        public void AddWaterImage(string oldImagePath, string waterImagePath, string newImageSavePath, Point point)
        {
            if (!File.Exists(oldImagePath))
            {
                return;
            }
            Stream s = File.Open(oldImagePath, FileMode.Open);
            AddWaterImage(s, waterImagePath, newImageSavePath, point);
            s.Close();
        }
        /// <summary>
        /// 添加水印图片
        /// </summary>
        /// <param name="oldImage">要添加水印图片的图片的文件流</param>
        /// <param name="waterImagePath">水印图片绝对路径</param>
        /// <param name="newImageSavePath">新图片保存路径</param>
        /// <param name="point">水印图片左上角位置</param>
        public void AddWaterImage(Stream oldImage, string waterImagePath, string newImageSavePath, Point point)
        {
            if (!File.Exists(waterImagePath))
            {
                return;
            }
            System.Drawing.Image waterimage = System.Drawing.Image.FromFile(waterImagePath);
            System.Drawing.Image oldimage = System.Drawing.Image.FromStream(oldImage);
            var graphics = Graphics.FromImage(oldimage);
            var imgAttributes = new ImageAttributes();
            var colorMap = new ColorMap
                {
                    OldColor = Color.FromArgb(255, 0, 255, 0),
                    NewColor = Color.FromArgb(0, 0, 0, 0)
                };
            ColorMap[] remapTable = { colorMap };
            imgAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
            float[][] colorMatrixElements = { 
                                   new[] {1.0f,  0.0f,  0.0f,  0.0f, 0.0f},
                                   new[] {0.0f,  1.0f,  0.0f,  0.0f, 0.0f},
                                   new[] {0.0f,  0.0f,  1.0f,  0.0f, 0.0f},
                                   new[] {0.0f,  0.0f,  0.0f,  0.5f, 0.0f},//透明度:0.5
                                   new[] {0.0f,  0.0f,  0.0f,  0.0f, 1.0f}
                                };
            var wmColorMatrix = new ColorMatrix(colorMatrixElements);
            imgAttributes.SetColorMatrix(wmColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
            graphics.DrawImage(waterimage, new Rectangle(point.X, point.Y, waterimage.Width, waterimage.Height), 0, 0, waterimage.Width, waterimage.Height, GraphicsUnit.Pixel, imgAttributes);
            oldimage.Save(newImageSavePath);
            oldimage.Dispose();
            waterimage.Dispose();
            graphics.Dispose();
        }
        /// <summary>
        /// 添加文字
        /// </summary>
        /// <param name="oldImagePath">要添加文字的图片的绝对位置</param>
        /// <param name="waterString">文字</param>
        /// <param name="newImageSavePath">新图片保存路径</param>
        /// <param name="point">文字左上角位置</param>
        public void AddStringToImage(string oldImagePath, string waterString, string newImageSavePath, Point point)
        {
            if (!File.Exists(oldImagePath))
            {
                return;
            }
            Stream s = File.Open(oldImagePath, FileMode.Open);
            AddStringToImage(s, waterString, newImageSavePath, point);
            s.Close();
        }
        /// <summary>
        /// 添加文字
        /// </summary>
        /// <param name="oldImage">要添加文字的图片的文件流</param>
        /// <param name="waterString">文字</param>
        /// <param name="newImageSavePath">新图片保存路径</param>
        /// <param name="point">文字左上角位置</param>
        public void AddStringToImage(Stream oldImage, string waterString, string newImageSavePath, Point point)
        {
            System.Drawing.Image oldimage = System.Drawing.Image.FromStream(oldImage);
            var graphics = Graphics.FromImage(oldimage);
            var font = new Font("Arial", 30, FontStyle.Bold);
            var brush = new LinearGradientBrush(new Rectangle(point.X, point.Y, 50, 20), Color.FromArgb(50, 0, 0, 0), Color.FromArgb(100, 0, 0, 0), 1.2f, true);
            graphics.DrawString(waterString, font, brush, point);
            oldimage.Save(newImageSavePath);
            font.Dispose();
            brush.Dispose();
            graphics.Dispose();
        }


        /// <summary>
        /// 转换成gif透明图片
        /// </summary>
        /// <param name="myBitMap"></param>
        /// <returns></returns>
        public Bitmap ToImageGif(Bitmap myBitMap)
        {
            int width = myBitMap.Width;
            int height = myBitMap.Height;

            MemoryStream memoryStream = new MemoryStream();
            myBitMap.Save(memoryStream, ImageFormat.Gif);
            Bitmap myBitMap256 = (Bitmap)System.Drawing.Image.FromStream(memoryStream);  //保存成GIF 256色
            memoryStream.Dispose();
            //获取颜色索引
            ColorPalette colorPalette = myBitMap256.Palette;
            Hashtable colorHash = new Hashtable();
            for (int i = 0; i != colorPalette.Entries.Length; i++)
            {

                string key = colorPalette.Entries[i].R.ToString("X02") + colorPalette.Entries[i].G.ToString("X02") + colorPalette.Entries[i].B.ToString("X02");

                if (colorHash[key] == null) colorHash.Add(key, i);
            }

            ////建立新的图形
            Bitmap newbitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
            newbitmap.Palette = colorPalette;  //设置索引
            Rectangle rect = new Rectangle(0, 0, width, height);
            //获取IMAGE数据
            BitmapData bitmapData = newbitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
            byte[] bits = new byte[width * height];
            Int32 bitsInt;
            if (bitmapData.Stride > 0)
            {
                bitsInt = bitmapData.Scan0.ToInt32();
            }
            else
            {
                bitsInt = bitmapData.Scan0.ToInt32() + bitmapData.Stride * (height - 1);
            }
            int stride = Math.Abs(bitmapData.Stride);
            for (int i = 0; i != height; i++)
            {
                for (int y = 0; y != width; y++)
                {
                    int _8BppPixel = i * stride + y;
                    Color tempColor = myBitMap256.GetPixel(y, i);
                    int alpha = myBitMap.GetPixel(y, i).A;
                    if (alpha == 0)
                    {
                        bits[_8BppPixel] = 16;
                    }
                    else
                    {
                        string key = tempColor.R.ToString("X02") + tempColor.G.ToString("X02") + tempColor.B.ToString("X02");
                        object valueIndex = colorHash[key];
                        if (valueIndex != null)
                        {
                            bits[_8BppPixel] = (byte)((int)valueIndex);
                        }
                    }
                }
            }
            CopyArrayTo(bitsInt, bits, height * stride);
            newbitmap.UnlockBits(bitmapData);
            return newbitmap;
        }

        [DllImport("KERNEL32.DLL", EntryPoint = "RtlMoveMemory", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern void CopyArrayTo([In(), MarshalAs(UnmanagedType.I4)] Int32 hpvDest, [In(), Out()]byte[] hpvSource, int cbCopy);


    }
    public struct WidthHeight
    {
        public int Width;
        public int Height;
    }
}
